Repository navigation
[YAML] Add SplunkIO write SchemaTransform and WriteToSplunk - #40481
schizophrenicmaniac wants to merge 9 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #40481 +/- ##
=============================================
- Coverage 80.04% 58.83% -21.22%
- Complexity 0 13972 +13972
=============================================
Files 490 2601 +2111
Lines 82916 273357 +190441
Branches 0 11287 +11287
=============================================
+ Hits 66373 160830 +94457
- Misses 16543 106510 +89967
- Partials 0 6017 +6017
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Assigning reviewers: R: @jrmccluskey for label python. Note: If you would like to opt out of this review, comment Available commands:
The PR bot will only process comments in the main thread (not review comments). |
|
waiting on author |
|
Merged master and resolved the CHANGES.md conflict, keeping both entries. |
derrickaw
left a comment
There was a problem hiding this comment.
A few comments on yaml related code.
|
LGTM for yaml/python @kennknowles, can you review the java part? Thanks |
| .apply("Create KV pairs", CreateKeys.of(parallelism())) | ||
| .apply("Write Splunk events", ParDo.of(writer)); | ||
| .apply("Write Splunk events", ParDo.of(writer)) | ||
| .setCoder(SplunkWriteErrorCoder.of()); |
There was a problem hiding this comment.
As you've probably noticed, the trouble with this is that it requires a special wrapper to be encoded as a row to be used by other languages. This is not such a terrible thing, but it would be better to do a hand-written schema coder so that SplunkWriteError is still encoded as a row, it just cannot use the @AutoValueSchema annotation to do it (though fixing the get-prefix limitation might be a one-shot prompt...)
This would look like making a new SchemaCoder(toFunction, fromFunction) where the to/from are just the same logic that you have in the SchemaTransform wrapper.
Does this work? Am I overlooking at issue?
Aside: if we were to switch to the new coder since the @AutoValueSchema annotation is not working as intended, we should replace it in the other file like so:
@DefaultCoder(SplunkWriteErrorCoder.class)
public class SplunkWriteError {
...
}
Then the coder will be automatic, here and everywhere.
But again, I think we can keep it encoded as a row so we don't have the breaking change and it works smoothly with the schema transform.
There was a problem hiding this comment.
Yes, that works. I dropped SplunkWriteErrorCoder and added a SplunkWriteErrorSchemaProvider with hand-written to/from row functions (fields statusCode, statusMessage, payload). SplunkWriteError now uses it via @DefaultSchema instead of AutoValueSchema, so the setCoder call in SplunkIO.Write is gone and the output is inferred as a SchemaCoder like before, just with actual fields now. The schema transform still builds its own error rows since it adds failed_row.
I didn't touch the get-prefix handling in AutoValueSchema. That would change the inferred schema, and so the coder, of any other AutoValue type that has non-get accessors, so it seemed better kept out of this PR.
|
@kennknowles I switched SplunkWriteError over to a hand-written schema provider as you suggested, could you take another look when you get a chance? |
kennknowles
left a comment
There was a problem hiding this comment.
OK I took another look. Definitely an improvement! I see some other things that seem worth cleaning up.
|
|
||
| Schema errorSchema = | ||
| Schema.builder() | ||
| .addNullableRowField("failed_row", inputRows.getSchema()) |
There was a problem hiding this comment.
Is this duplicate with the SplunkWriteErrorSchemaProvider?
There was a problem hiding this comment.
Partly. It's the same three fields plus failed_row. I changed it to take those fields from SplunkWriteErrorSchemaProvider.SCHEMA and build both kinds of error rows through the provider's toRow, so they're only defined in one place now.
|
|
||
| assertEquals( | ||
| Schema.builder() | ||
| .addNullableField("statusCode", Schema.FieldType.INT32) |
There was a problem hiding this comment.
This seems like just a duplicate of the code in the schema provider. Is there something being tested here?
There was a problem hiding this comment.
Not really. It only checks that the annotation picks up the provider, and the coder round trip and to/from row tests already cover that. Removed it.
| # fallback URN. The payload is the snappy-compressed serialized Java coder, | ||
| # and the start of its class name stays uncompressed, so it can be used to | ||
| # tell the two apart. | ||
| if b'VarInt' in payload: |
There was a problem hiding this comment.
This seems like a major hack. What is the goal here? If there is a "standard coder" that is accidentally being serialized as beam:coders:javasdk then we should fix that in the Java SDK.
There was a problem hiding this comment.
Agreed, it was a hack. The goal was to get the YAML test running on the Python FnApiRunner. SplunkIO keys its stateful writer with VarIntCoder, which has no portable URN, so it isn't a standard coder being serialized wrongly. The actual problem was in the runner: FnApiRunner length prefixes coders it doesn't know for PCollections, but not for timer family coders, so it tried to decode the Java timer keys itself. That's also why the BigEndianIntegerCoder registration for Datadog was there.
I changed setup_timer_mapping in translations.py to length prefix the timer coders the same way, so the runner treats those keys as bytes, and added a test for it. With that, the Splunk and Datadog YAML tests both pass without any beam:coders:javasdk:0.1 registration, so I removed it from integration_tests.py, the BigEndianIntegerCoder one included.
…rs in FnApiRunner
|
@kennknowles I've addressed your latest comments, could you take another look? The two red checks aren't from this change: BigQueryNestedRecordsIT hit a 503 backendError from BigQuery, and codecov/patch is flagging splunk_test_utils.py, which only runs in the YAML integration tests. |
…io-for # Conflicts: # CHANGES.md
kennknowles
left a comment
There was a problem hiding this comment.
This looks pretty good. There are merge conflicts to be resolved, so that'll kick the tests off again anyhow. We'll get them green before merge.
Adds a SchemaTransform for SplunkIO writes and exposes it in Beam YAML as
WriteToSplunk. It follows the same approach as the Datadog one (#38362). SplunkIO in Java only supports writes, so there is noReadFromSplunkhere.Each input row becomes a
SplunkEvent.event(string) is required.time(int64),host,source,sourcetype,indexandfieldsare optional.fieldscan be a nested row or a JSON object string, and other columns are ignored. The config covers everythingSplunkIO.Writesupports (url, token, batch_count, parallelism, disable_certificate_validation, root_ca_certificate_path, enable_batch_logs, enable_gzip_http_compression) plus error_handling. The error output has the same shape as Datadog's: rows that can't be converted come back withfailed_rowand a 400, and HEC write failures come back with the HTTP status and the payload. Without error_handling, a failed write fails the pipeline.While testing this I found that
SplunkWriteErrorloses all of its values once it goes through a coder. It has@DefaultSchema(AutoValueSchema.class), but its accessors aren'tget-prefixed, so the inferred schema has no fields and every error decodes as null/null/null.SplunkEventWriterTestdoesn't catch this becausecontainsInAnyOrderdecodes both sides with the same coder. I replaced the annotation with a hand-writtenSplunkWriteErrorSchemaProvider, soSplunkWriteErroris still encoded as a row, now withstatusCode,statusMessageandpayloadfields. This changes the output coder ofSplunkIO.Write, so I listed it under bugfixes in CHANGES.md.The YAML test runs SplunkIO on the Python FnApiRunner, which failed on the stateful writer's timers: the runner length prefixes coders it doesn't know for PCollections but not for timer family coders, so it tried to decode the Java
VarIntCoderkeys itself. The runner now length prefixes timer coders the same way. This also makes thebeam:coders:javasdk:0.1registration in integration_tests.py unnecessary, so that's removed.Changes:
SplunkWriteSchemaTransformProvider/SplunkWriteSchemaTransformConfiguration, registered in the IO expansion serviceWriteToSplunkin standard_io.yaml and the matching entry in standard_external_transforms.yamlSplunkWriteErrorSchemaProvider, used as the default schema ofSplunkWriteErrorand for the fields of the error outputFixes #40470